`timescale 1ns / 1ps

module SCCPUSOC_Top(
        input   clk,
        input   rstn,
        input  [15:0] sw_i, // output to switch
        output [7:0] disp_seg_o, disp_an_o // output to seg7
   );
  
   wire Clk_CPU;        // CPU clock
   wire [31:0]  instr;  // instruction
   wire [31:0]  PC;     // PC
   wire MemWrite;       // memory write
   wire [31:0]  dm_din, dm_dout; // data 
   
   wire rst;
   assign rst = ~rstn;

   wire [31:0]  seg7_data; 
   wire [6:0]  ram_addr;
   wire ram_we;
   wire seg7_we;
   
   wire [31:0]  cpu_data_out;       // data from CPU
   wire [31:0]  cpu_data_addr;
   wire [31:0]  ram_data_out;
   wire [31:0]  cpu_data_in;
   wire [31:0]  cpuseg7_data;
   wire [31:0]  reg_data;
   
  // instantiation of clock divisor  
   clk_div U_CLKDIV( 
         .clk(clk),       // board clock
         .rst(rst),       // reset 
         .SW15(sw_i[15]), // sw15
         .Clk_CPU(Clk_CPU)// cpu clock
         );
         
  // instantiation of single-cycle cpu       
   sccpu U_SCCPU(
         .clk(Clk_CPU),             // cpu clock
         .rst(rst),                 // reset
         .instr(instr),             // instruction
         .readdata(cpu_data_in),    // data from meory/IO to cpu  
         .MemWrite(MemWrite),       // memory/IO(seg7) write signal
         .PC(PC),                   // PC
         .aluout(cpu_data_addr),    // address from cpu to memory/IO(seg7)
         .writedata(cpu_data_out),  // data from cpu to memory/IO
         .reg_sel(sw_i[4:0]),       // register selection
         .reg_data(reg_data)        // register data
         );

  // instantiation of intruction memory (used for FPGA), imem is generated by IP core
   imem  U_IM(
         .a(PC[8:2]), .spo(instr)
         );

  // instantiation of data memory  
   dm    U_DM(
         .clk(Clk_CPU),   // cpu clock
         .DMWr(ram_we),   // ram write
         .addr(ram_addr), // ram address
         .din(dm_din),    // data to ram
         .dout(dm_dout)   // data from ram
         );

  // instantiation of MIO_BUS
   MIO_BUS  U_MIO (
         .sw_i(sw_i),                   // switch
         .mem_w(MemWrite),              // memory/IO(seg7) write signal
         .cpu_data_out(cpu_data_out),   // data from cpu to memory/IO 
         .cpu_data_addr(cpu_data_addr), // address from cpu to memory/IO(seg7)
         .ram_data_out(dm_dout),        // data from ram 
         .cpu_data_in(cpu_data_in),     // data from memory/IO to cpu
         .ram_data_in(dm_din),          // data to ram
         .ram_addr(ram_addr),           // ram address
         .cpuseg7_data(cpuseg7_data),   // data from cpu to seg7
         .ram_we(ram_we),               // memory write signal
         .seg7_we(seg7_we)              // seg7 write signal
   );
   
  // instantiation of Multi_CH32
   Multi_CH32 U_Multi (
          .clk(clk),                        // board clk
          .rst(rst),                        // reset
          .EN(seg7_we),                     // seg7 write enable
          .ctrl(sw_i[5:0]),                 // SW[5:0]
          .Data0(cpuseg7_data),             // channel 0 (data from cpu to seg7)
           //disp_cpudata
          .data1({2'b0,PC[31:2]}),          // test channel 1--instruction no.
          .data2(PC),                       // test channel 2--PC
          .data3(instr),                    // test channel 3--instruction
          .data4(cpu_data_addr),            // test channel 4--address from cpu to memory/IO(seg7)
          .data5(cpu_data_out),             // test channel 5--data from cpu to memory/IO
          .data6(dm_dout),                  // test channel 6--data from ram
          .data7({23'b0, ram_addr, 2'b00}), // test channel 7--ram address
          .reg_data(reg_data),              // selected register data
          .seg7_data(seg7_data)             // data to seg7 display
          );
            
  // instantiation of 16 seg7 displays             
   seg7x16 U_7SEG(
         .clk(clk),           // board clock
         .rst(rst),           // reset
         .cs(1'b1),           // selection (always 1)
         .i_data(seg7_data),  // data to seg7 display
         .o_seg(disp_seg_o),  // to board disp_seg_o
         .o_sel(disp_an_o)    // to board disp_an_o
         );

endmodule
